package parserjc.jaccie;

import java.util.*;

/**
 * The input of a scanner.
 *
 * @author Christoph Reich
 * @version 1.00 04. jun 1997
 */
public class ScannerInput {

String ls = System.getProperty("line.separator");
/**
 * The input string.
 */
private String input;

/**
 * The last valid characters position number in the input.
 */
private int lastValidCharAt = 0;

/**
 * The current input string index.
 */
private int stringIndex = 0;

/**
 * The comments of the scanner definition. The JACCIE scanner allows to
 * define comments. This comments have start string and an end string.
 * By a lineComment the end String is newLine.
 */
private String[][] comments;

/**
 * The verbatims of the scanner definition. The JACCIE scanner allows to
 * define verbatims. This verbatims have start string and an end string.
 */
private String[][] verbatims;

/**
 * The last recognized token has a position (index) in the input string.
 * The positions, of all last regognized token will be keep in this vector.
 * The contents are Integers
 */
private Vector lastTokenPos = new Vector();

/**
 * The indixes where a new line character is in the input string.
 * This information is needed for the current line number.
 * The contents are Integers
 */
private Vector lines = new Vector();

    /**
     * Sets an input string. The input will be trimed and the
     * lines vector will be filled.
     */
    public void setInput(String input) {
        input = input.trim();
        this.input = input;
        this.stringIndex = 0;
        this.lastValidCharAt = 0;
        this.lastTokenPos.addElement(new Integer(0));
        lines.removeAllElements();
        int newlinePos = 0;
        do {
            newlinePos = input.indexOf("\n",newlinePos);
            if (newlinePos != -1) decLine(newlinePos++);
            else break;
        } while(true);
    }

    /**
     * Fills the line vector with an Integer.
     */
    private void decLine(int index) {
        if (index != -1)
        lines.addElement(new Integer(index));
    }

    /**
     * @return the current line number
     */
    public int getLineNumber() {
        int lineNumber = 0;
        for (int i=0; i<lines.size(); i++) {
            int lineIndex = ((Integer)lines.elementAt(i)).intValue();
            if (stringIndex > lineIndex) {
                lineNumber++;
            }
            else break;
        }
        return lineNumber;
    }

    /**
     * @return the current column number depend of the line number
     */
    public int getColumnNumber() {
        int columnNumber = 0;
        int lineNumber = getLineNumber();
        if (lineNumber == 0) return stringIndex;
        else {
            int lineIndex = ((Integer)lines.elementAt(lineNumber-1)).intValue();
            return stringIndex-lineIndex-1;
        }
    }

    /**
     * Resets the scanner input.
     */
    public void reset() {
        this.stringIndex = 0;
        this.lastValidCharAt = 0;
        this.lastTokenPos.removeAllElements();
        this.lastTokenPos.addElement(new Integer(0));
    }

    /**
     * Sets the comments.
     */
    public void setComments(String[][] comments) {
        this.comments = comments;
    }

    /**
     * Sets the verbatims
     */
    public void setVerbatims(String[][] verbatims) {
        this.verbatims = verbatims;
    }

    /**
     * @return the end string (right side) of the start string
     * @param leftSide the start string
     * If no end string is founded the left string will return.
     */
    public String getComment(String leftSide) {
        for (int i=0; i<comments.length; i++) {
            if (comments[i][0].equals(leftSide))
                return comments[i][1];
        }
        return leftSide;
    }

    /**
     * @return the string between the current input index and
     * a border string. A double border string will be overread.
     * The input index will be set to the new index after the founded
     * border string. Is no border string founded the method returns
     * the string between the current input index and the length of input.
     */
    public String getString(String borderChar) {
        String stringToken = input.substring(stringIndex);
        String testString = borderChar+borderChar;
        int index = stringToken.indexOf(testString);
        int oldIndex = 0;
        int cut = 0;
        while (index != -1) {
              stringToken = stringToken.substring(0,index)+
                            stringToken.substring(index+borderChar.length());
              index += borderChar.length();
              oldIndex = index;
              cut++;
              index = stringToken.indexOf(testString,index);
        }
        index = stringToken.indexOf(borderChar,oldIndex);
        if (index != -1) {
            stringToken = stringToken.substring(0,index);
            cut++;
            stringIndex += index + (cut*borderChar.length());
            return stringToken;
        }
        else {
            stringIndex = input.length();
            return stringToken;
        }
    }

    /**
     * @return the string between the verbatim start string and
     * the verbatim end string. If no verbatim end string is defined
     * the end string is the start string. If no end string foundet in
     * the input after the current position, the string between start
     * string and end of input will be return.
     * @param leftSide the start string
     */
    public String getVerbatim(String leftSide) {
        for (int i=0; i<verbatims.length;i++) {
            if (verbatims[i][0].equals(leftSide))
                return getString(verbatims[i][1]);
        }
        return getString(leftSide);
    }

    /**
     * Adds the current index of the input string minus a specified value
     * to the lastTokenPos vector. This method will be called when a token is
     * accumulated.
     * @param dex corrects the last token pos
     */
    public void setLastTokenPos(int dex) {
        this.lastTokenPos.addElement(new Integer(stringIndex-dex));
    }

    /**
     * @return the last added last-accumulated-token-position or 0
     * if no more accumulated token in the vector
     * @param remove is true then the returned value will be delete from the vector.
     */
    public Integer getLastTokenPos(boolean remove) {
        if(!lastTokenPos.isEmpty()) {
            Integer pos = (Integer)lastTokenPos.lastElement();
            if (remove)
                lastTokenPos.removeElementAt(lastTokenPos.size()-1);
            return pos;
        }
        else return new Integer(0);
    }

    /**
     * @return the current input index.
     */
    public int getCurrentPosition() {
        return stringIndex;
    }

    /**
     * Sets the valid char to the current string index minus 1.
     */
    public void setValidChar() {
        lastValidCharAt = stringIndex-1;
    }

    /**
     * @return the character of the input string where the stringIndex points
     * to. If there is no more character it returns null.
     */
    public Character getChar() {
        if (stringIndex < input.length()) {
            Character currentChar = new Character(input.charAt(stringIndex));
            stringIndex++;
            return currentChar;
        }
        else return null;
    }

    /**
     * Points the input index pointer after the next specified find string.
     * @param find the string to find.
     */
    public void skipUntil(String find) {
        if (find.equals("JACCIE_EndOfLine")) find = ls;
        int index = input.indexOf(find,stringIndex);
        if (index != -1)
            stringIndex = index + find.length();
        else stringIndex = input.length();
    }

    /**
     * Points the input index to the lastValidChar index.
     */
    public void setIndex() {
        stringIndex = lastValidCharAt;
    }

    /**
     * Points the input to the specified position.
     */
    public void setIndex(int position) {
        stringIndex = position;
        lastValidCharAt = position;
    }

     /**
     * @return a string needed for building a java application
     */
    public String toString() {
        String string = new String();
        if (verbatims != null) {
            string += "     String[][] verbatims = new String[";
            string += verbatims.length +"][2];"+ls;
            for (int i=0; i< verbatims.length; i++) {
                string += "     verbatims["+ i +"][0] = \"";
                string += verbatims[i][0] + "\";"+ls;
                string += "     verbatims["+ i +"][1] = \"";
                string += verbatims[i][1] + "\";"+ls;
            }
            string += "     input.setVerbatims(verbatims);"+ls;
        }
        if (comments != null) {
            string += "     String[][] comments = new String[";
            string += comments.length +"][2];"+ls;
            for (int i=0; i< comments.length; i++) {
                string += "     comments["+ i +"][0] = \"";
                string += comments[i][0] + "\";"+ls;
                string += "     comments["+ i +"][1] = \"";
                string += comments[i][1] + "\";"+ls;
            }
            string += "     input.setComments(comments);"+ls;
        }
        return string;
    }

}